Clean the pending_intr processing sequence and fix some potential bugs.
authorkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Fri, 10 Mar 2006 08:12:22 +0000 (09:12 +0100)
committerkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Fri, 10 Mar 2006 08:12:22 +0000 (09:12 +0100)
Signed-off-by: Eddie Dong <eddie.dong@intel.com>
Signed-off-by: Xiaowei Yang <xiaowei.yang@intel.com>
xen/arch/x86/hvm/vlapic.c
xen/arch/x86/hvm/vmx/io.c
xen/arch/x86/hvm/vmx/vmcs.c
xen/arch/x86/hvm/vmx/vmx.c
xen/include/asm-x86/hvm/io.h
xen/include/asm-x86/hvm/vlapic.h
xen/include/asm-x86/hvm/vmx/vmcs.h

index 10d72843421a54737c73746008a171507b89496d..89cd82afd70562732b07f8554ead78f8de78549a 100644 (file)
@@ -943,6 +943,20 @@ int cpu_get_apic_interrupt(struct vcpu *v, int *mode)
     return -1;
 }
 
+int cpu_has_apic_interrupt(struct vcpu* v)
+{
+    struct vlapic *vlapic = VLAPIC(v);
+
+    if (vlapic && vlapic_enabled(vlapic)) {
+        int highest_irr = vlapic_find_highest_irr(vlapic);
+
+        if (highest_irr != -1 && highest_irr >= vlapic->processor_priority) {
+            return 1;
+        }
+    }
+    return 0;
+}
 void vlapic_post_injection(struct vcpu *v, int vector, int deliver_mode)
 {
     struct vlapic *vlapic = VLAPIC(v);
index 6c129f34e0f36a759acce6f2aa1c80578c5b37e3..38ffa0a5d1b54463a12ca7745fb322444ccff2e9 100644 (file)
@@ -86,28 +86,53 @@ interrupt_post_injection(struct vcpu * v, int vector, int type)
 }
 
 static inline void
-enable_irq_window(unsigned long cpu_exec_control)
+enable_irq_window(struct vcpu *v)
 {
-    if (!(cpu_exec_control & CPU_BASED_VIRTUAL_INTR_PENDING)) {
-        cpu_exec_control |= CPU_BASED_VIRTUAL_INTR_PENDING;
-        __vmwrite(CPU_BASED_VM_EXEC_CONTROL, cpu_exec_control);
+    u32  *cpu_exec_control = &v->arch.hvm_vcpu.u.vmx.exec_control;
+    
+    if (!(*cpu_exec_control & CPU_BASED_VIRTUAL_INTR_PENDING)) {
+        *cpu_exec_control |= CPU_BASED_VIRTUAL_INTR_PENDING;
+        __vmwrite(CPU_BASED_VM_EXEC_CONTROL, *cpu_exec_control);
     }
 }
 
 static inline void
-disable_irq_window(unsigned long cpu_exec_control)
+disable_irq_window(struct vcpu *v)
 {
-    if ( cpu_exec_control & CPU_BASED_VIRTUAL_INTR_PENDING ) {
-        cpu_exec_control &= ~CPU_BASED_VIRTUAL_INTR_PENDING;
-        __vmwrite(CPU_BASED_VM_EXEC_CONTROL, cpu_exec_control);
+    u32  *cpu_exec_control = &v->arch.hvm_vcpu.u.vmx.exec_control;
+    
+    if ( *cpu_exec_control & CPU_BASED_VIRTUAL_INTR_PENDING ) {
+        *cpu_exec_control &= ~CPU_BASED_VIRTUAL_INTR_PENDING;
+        __vmwrite(CPU_BASED_VM_EXEC_CONTROL, *cpu_exec_control);
     }
 }
 
+static inline int is_interruptibility_state(void)
+{
+    int  interruptibility;
+    __vmread(GUEST_INTERRUPTIBILITY_INFO, &interruptibility);
+    return interruptibility;
+}
+
+/* check to see if there is pending interrupt  */
+int cpu_has_pending_irq(struct vcpu *v)
+{
+    struct hvm_domain *plat = &v->domain->arch.hvm_domain;
+
+    /* APIC */
+    if ( cpu_has_apic_interrupt(v) ) return 1;
+    
+    /* PIC */
+    if ( !vlapic_accept_pic_intr(v) ) return 0;
+
+    return plat->interrupt_request;
+}
+
 asmlinkage void vmx_intr_assist(void)
 {
     int intr_type = 0;
     int highest_vector;
-    unsigned long intr_fields, eflags, interruptibility, cpu_exec_control;
+    unsigned long eflags;
     struct vcpu *v = current;
     struct hvm_domain *plat=&v->domain->arch.hvm_domain;
     struct hvm_virpit *vpit = &plat->vpit;
@@ -121,37 +146,21 @@ asmlinkage void vmx_intr_assist(void)
         pic_set_irq(pic, 0, 1);
     }
 
-    __vmread_vcpu(v, CPU_BASED_VM_EXEC_CONTROL, &cpu_exec_control);
-    __vmread(VM_ENTRY_INTR_INFO_FIELD, &intr_fields);
+    if ( !cpu_has_pending_irq(v) ) return;
 
-    if (intr_fields & INTR_INFO_VALID_MASK) {
-        enable_irq_window(cpu_exec_control);
-        HVM_DBG_LOG(DBG_LEVEL_1, "vmx_intr_assist: intr_fields: %lx",
-                    intr_fields);
-        return;
-    }
-
-    __vmread(GUEST_INTERRUPTIBILITY_INFO, &interruptibility);
-
-    if (interruptibility) {
-        enable_irq_window(cpu_exec_control);
-        HVM_DBG_LOG(DBG_LEVEL_1, "interruptibility: %lx",interruptibility);
+    if ( is_interruptibility_state() ) {    /* pre-cleared for emulated instruction */
+        enable_irq_window(v);
+        HVM_DBG_LOG(DBG_LEVEL_1, "interruptibility");
         return;
     }
 
     __vmread(GUEST_RFLAGS, &eflags);
     if (irq_masked(eflags)) {
-        enable_irq_window(cpu_exec_control);
+        enable_irq_window(v);
         return;
     }
 
     highest_vector = cpu_get_interrupt(v, &intr_type); 
-
-    if (highest_vector == -1) {
-        disable_irq_window(cpu_exec_control);
-        return;
-    }
-
     switch (intr_type) {
     case VLAPIC_DELIV_MODE_EXT:
     case VLAPIC_DELIV_MODE_FIXED:
index b75507506355854b02ff9de36e140801ef9d492c..ce0e8031ebaba7709cec6becf4e814e2b93a364e 100644 (file)
@@ -219,6 +219,7 @@ static void vmx_do_launch(struct vcpu *v)
     error |= __vmwrite(CR0_READ_SHADOW, cr0);
     error |= __vmwrite(CPU_BASED_VM_EXEC_CONTROL,
                        MONITOR_CPU_BASED_EXEC_CONTROLS);
+    v->arch.hvm_vcpu.u.vmx.exec_control = MONITOR_CPU_BASED_EXEC_CONTROLS;
 
     __asm__ __volatile__ ("mov %%cr4,%0" : "=r" (cr4) : );
 
index 05a099e2c1af41b451752ed620d8621c4ea969b3..77310e5146e74be3ad53bd717a5231057738635c 100644 (file)
@@ -595,6 +595,7 @@ static void inline __update_guest_eip(unsigned long inst_len)
 
     __vmread(GUEST_RIP, &current_eip);
     __vmwrite(GUEST_RIP, current_eip + inst_len);
+    __vmwrite(GUEST_INTERRUPTIBILITY_INFO, 0);
 }
 
 
@@ -2025,6 +2026,7 @@ asmlinkage void vmx_vmexit_handler(struct cpu_user_regs regs)
     case EXIT_REASON_PENDING_INTERRUPT:
         __vmwrite(CPU_BASED_VM_EXEC_CONTROL,
                   MONITOR_CPU_BASED_EXEC_CONTROLS);
+        v->arch.hvm_vcpu.u.vmx.exec_control = MONITOR_CPU_BASED_EXEC_CONTROLS;
         break;
     case EXIT_REASON_TASK_SWITCH:
         __hvm_bug(&regs);
index 46698d055cec1d55c3fedf737cfc3ba4ea2e4a66..224f22cc4a6d56af7f47194385fe97411b0282b5 100644 (file)
@@ -154,6 +154,7 @@ extern void hvm_io_assist(struct vcpu *v);
 extern void pic_irq_request(int *interrupt_request, int level);
 extern void hvm_pic_assist(struct vcpu *v);
 extern int cpu_get_interrupt(struct vcpu *v, int *type);
+extern int cpu_has_pending_irq(struct vcpu *v);
 
 // XXX - think about this, maybe use bit 30 of the mfn to signify an MMIO frame.
 #define mmio_space(gpa) (!VALID_MFN(get_mfn_from_gpfn((gpa) >> PAGE_SHIFT)))
index 2f8a4f7b14f088e70c185290759371bd125b1252..95ee810a8b5ed339c7dbb77b47d5052be58abdf8 100644 (file)
@@ -209,6 +209,7 @@ static uint32_t inline vlapic_get_base_address(struct vlapic *vlapic)
 
 void vlapic_post_injection(struct vcpu* v, int vector, int deliver_mode);
 
+int cpu_has_apic_interrupt(struct vcpu* v);
 int cpu_get_apic_interrupt(struct vcpu* v, int *mode);
 
 extern uint32_t vlapic_update_ppr(struct vlapic *vlapic);
index 54820bcb2b1f07d47d09b862abb49b58ab6ff1ff..703ae090f34479c7d1c2419f6e9e459e2bce2045 100644 (file)
@@ -69,6 +69,7 @@ struct vmx_msr_state {
 struct arch_vmx_struct {
     struct vmcs_struct      *vmcs;  /* VMCS pointer in virtual. */
     unsigned int            launch_cpu; /* VMCS is valid on this CPU. */
+    u32                     exec_control; /* cache of cpu execution control */
     unsigned long           flags;  /* VMCS flags */
     unsigned long           cpu_cr0; /* copy of guest CR0 */
     unsigned long           cpu_shadow_cr0; /* copy of guest read shadow CR0 */